%%------------------------------------------------------------------------------
% @doc kvcache module
% @author hgx <hgx@live.cn>
% @copyright 2024 hgx, All rights reserved.
% @since 2024-05-21 
%%------------------------------------------------------------------------------
-module(kvcache).

-export([set_kv/2, get_kv/1, cache/2]).
-export([clean_all/0]).
-export([timecallback/0]).
-export([set_timeout/1]).



%% public functions
%% 一般调用方法，适用于自定义 key
-spec set_kv(Key :: term(), Value :: term()) -> ok.
set_kv(Key, Value) ->
    gen_server:cast(kvcache_worker, {set_kv, Key, Value}).

-spec get_kv(Key :: term()) -> undefined | Value :: term().
get_kv(Key) ->
    case ets:lookup(kvcache_worker, Key) of
        [{Key, Value}] ->
            gen_server:cast(kvcache_worker, {refresh, Key}),
            Value;
        _ ->
            undefined
    end.


%% 简便用法，无需指定 Key
-spec cache(Fun, Body) -> Value when
      Fun   :: fun((Body) -> Value),
      Body  :: term(),
      Value :: term().
cache(Fun, Body) when is_function(Fun, 1) ->
    %% 此处用透传函数做 Key，防止缓存内 Key 重复
    Key = {erlang:fun_to_list(Fun), Body},

    case get_kv(Key) of
        undefined ->
            Value = Fun(Body),
            set_kv(Key, Value),
            Value;
        Value ->
            Value
    end;
cache(_Fun, _Body) ->
    throw("The function kvcache:cache/2 first parameter is a function/1 .").


-spec clean_all() -> ok.
clean_all() ->
    gen_server:cast(kvcache_worker, clean_all).


-spec timecallback() -> ok.
timecallback() ->
    gen_server:cast(kvcache_worker, timecallback).


-spec set_timeout(Hour :: pos_integer()) -> ok.
set_timeout(Hour) when Hour > 0 ->
    gen_server:cast(kvcache_worker, {set_timeout, Hour});
set_timeout(_Hour) ->
    throw("The function kvcache:set_timeout/1 parameter is a number greater than zero.").

    
%% internal functions

